#include "common.hpp"

static const char *optString = "r:h?";

static const struct option longOpts[] = {
	{ "help", no_argument, NULL, 'h' },
//	{ "index", required_argument, NULL, 'i' },
	{ "resource", required_argument, NULL, 'r' },
	{ 0,0,0,0 }
};

int main (int argc, char* const argv[]) {
	srand( time(NULL) + getpid() );

	ipc::shared_memory_with_exceptions<size_t> listas	( my_ftok(COUNTER|LISTAS));

	ipc::semaphore_with_exceptions mutex_listas ( my_ftok(MUTEX|LISTAS),0);

	ipc::semaphore_with_exceptions mutex_tapadora ( my_ftok(MUTEX|TAPADORA),0);
	ipc::semaphore_with_exceptions mutex_etiquetadora ( my_ftok(MUTEX|ETIQUETADORA),0);

	ipc::messages_queue_with_exceptions llenadoras_salida ( my_ftok(MSG_QUEUE|LLENADORA_0) );
	ipc::messages_queue_with_exceptions tapadora_salida ( my_ftok(MSG_QUEUE|TAPADORA) );
//	ipc::messages_queue_with_exceptions etiquetadora_salida ( my_ftok(MSG_QUEUE|ETIQUETADORA) );
	ipc::messages_queue_with_exceptions repositor_salida ( my_ftok(MSG_QUEUE|REPOSITOR) );

	int longIndex = 0;
	int option = 0;
	bool ayuda = false;
	bool seguir = true;
	size_t procesadas = 0;
	long tapas = 0;

	// Interpretación de parametros.
	while ( (option = getopt_long(argc,argv,optString,longOpts,&longIndex) ) != EOF ) {
		switch (option) {
			case '?':
			case 'h':
			case ':':
				ayuda = true;
				break;
			case 'r':
				tapas = parse<long>(optarg,-1);
			default:
				break;
		}
	}

	if ( ayuda || tapas < 0) {
		std::cerr << "Proceso de control de un brazo con una tapadora de botellas llenas." << std::endl;
		std::cerr << "\tUso: " << argv[0] << " [-h] [-r natural]" << std::endl;
		std::cerr << "\tParametros:" << std::endl;
		std::cerr << "\t\t-h,--help:\tMostrar este mensaje de ayuda." << std::endl;
		std::cerr << "\t\t-r,--resource:\tNúmero de tapas disponibles en la estación." << std::endl;

		return (ayuda) ? 0 : -1;
	}

	sReposicion reposicion;

	sPedido pedir_tapas;
	pedir_tapas.tipo = PEDIR_RECURSO;
	pedir_tapas.origen = getpid();
	pedir_tapas.recurso = TAPA;
	pedir_tapas.sem_key = my_ftok(MUTEX|TAPADORA);
	pedir_tapas.sem_num = 0;

	sBotella tapada, entrante;
	tapada.tipo = BOTELLA;
	tapada.estado = TAPADA;

	try {
		listas.get(PERMITS);

		mutex_tapadora.get(PERMITS);
		mutex_etiquetadora.get(PERMITS);
		mutex_listas.get(PERMITS);

		llenadoras_salida.get(PERMITS);
		tapadora_salida.get(PERMITS);
		repositor_salida.get(PERMITS);

		logger.setColor(25+TAPADORA);
		logger << "Estación de tapado: Inicio." << nl;
		procesadas = 0;
		while (seguir) {
			//mutex_tapadora.wait();

			if (tapas > 0) {
				// Comprobar que existen botellas llenas.
				entrante.tipo = 0;
				llenadoras_salida.receive(entrante,BOTELLA);

				if (entrante.tipo == BOTELLA) {
					tapas--;
					procesadas++;
					logger << "Estación de tapado: Tapando botella " << entrante.id << "." << nl;
					// tapar botella.
					SIMULAR_TAPAR;

					// Enviar botella llena a la siguiente estación.
					switch (entrante.estado) {
						case LLENA: 
							tapada.id = entrante.id;
							tapadora_salida.send(tapada);
							logger << "Estación de tapado: Botella tapada "<< entrante.id<< "."<< " ("<< procesadas<< " en esta estación)."<< nl;
							break;
						case ETIQUETADA:
							// Enviar botella completada al almacen.
							mutex_listas.wait();
								(*listas)++;
							logger << "Estación de tapado: Botella terminada "<<entrante.id<<"."<<" ("<< procesadas<<" en esta estación)." << nl;
							mutex_listas.signal();
							break;
						default:
							error << "Estacion de tapado: Botella " << eEstadoToStr(entrante.estado) << "." << nl;
					}
				} else {
					error << "Estación de tapado: Ignorando respuesta incorrecta." << nl;
				}
			} else {
				logger << "Estación de tapado: Enviando pedido de reposición de tapas." << nl;
				repositor_salida.send(pedir_tapas);
				logger << "Estación de tapado: Detenida a la espera de tapas." << nl;
				mutex_tapadora.wait();
				reposicion.tipo = 0;
				repositor_salida.receive(reposicion,getpid());
			
				if ( (reposicion.tipo == getpid()) && (reposicion.recurso=TAPA) ) {
					tapas+= reposicion.cantidad;
					if (reposicion.cantidad > 0)
						logger << "Estación de tapado: Se recibio un pack de " << reposicion.cantidad << " tapas." << nl;
					else
						logger << "Estación de tapado: Se recibio un pack sin tapas." << nl;
				} else {
					error << "Estación de tapado: Ignorando respuesta de reposición incorrecta." << nl;
				}
			}
			//mutex_tapadora.signal();
		}

	} catch (ipc::exception& e) {
		logger << "Estacion de tapado: " << e.what() << "." << nl;
		exit(-1);
	}
	logger << "Estación de tapado: Fin." << nl;
	return 0;
}
